package com.eds.jwt.utils;


import com.eds.jwt.config.JwtKeyConfig;
import lombok.SneakyThrows;
import org.jose4j.json.JsonUtil;
import org.jose4j.jwa.AlgorithmConstraints;
import org.jose4j.jwk.RsaJsonWebKey;
import org.jose4j.jws.AlgorithmIdentifiers;
import org.jose4j.jws.JsonWebSignature;
import org.jose4j.jwt.JwtClaims;
import org.jose4j.jwt.consumer.JwtConsumer;
import org.jose4j.jwt.consumer.JwtConsumerBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/* *
 * @Title:
 * @Author: vvSmile
 * @Date: 2025-03-27 14:24:34
 * @param null

 * @Description: TODO Jwt生成Token
 */
@Component
public class JwtUtils {
    private static final String ISSUER = "vvSmile";
    private static final String AUDIENCE = "audience";
    private static JwtKeyConfig jwtKeyConfig;

    @SneakyThrows
    public static String sign(Long userId, String userName) {
        // 生成JWT声明
        JwtClaims claims = new JwtClaims();
        // 设置基本声明
        claims.setIssuer(ISSUER);// 签发者
        claims.setAudience(AUDIENCE);// 接收者
        claims.setExpirationTimeMinutesInTheFuture(60 * 24);// 设置过期时间
        claims.setGeneratedJwtId();// 设置JWT ID，用于标识该JWT
        claims.setIssuedAtToNow();// 设置当前时间
        claims.setNotBeforeMinutesInThePast(2);// 设置当前时间之前
        claims.setSubject("eds");// 主题
        // 设置用户信息
        claims.setClaim("userId", userId);// 用户ID
        claims.setClaim("userName", userName);// 用户名
        // 生成JWT
        JsonWebSignature jws = new JsonWebSignature();
        // 设置JWT声明
        jws.setPayload(claims.toJson());
        // 设置私钥和算法
        PrivateKey privateKey = new RsaJsonWebKey(JsonUtil.parseJson(jwtKeyConfig.getPrivateKeyJson())).getPrivateKey();
        // 设置私钥和算法
        jws.setKey(privateKey);
        // 设置JWT ID
        jws.setKeyIdHeaderValue("keyId");
        // 设置算法
        jws.setAlgorithmHeaderValue(AlgorithmIdentifiers.RSA_USING_SHA256);
        // 生成JWT
        return jws.getCompactSerialization();
    }

    @SneakyThrows
    public static Map<String, Object> verify(String token) {
        try {
            // 获取公钥
            PublicKey publicKey = new RsaJsonWebKey(JsonUtil.parseJson(jwtKeyConfig.getPublicKeyJson())).getPublicKey();
            // 创建Jwt验证器
            JwtConsumer jwtConsumer = new JwtConsumerBuilder()
                    // 设置验证规则
                    .setRequireExpirationTime()// 要求有过期时间
                    .setAllowedClockSkewInSeconds(30)// 允许时钟偏差
                    .setRequireSubject()// 要求有主题
                    .setExpectedIssuer(ISSUER)// 签发者
                    .setExpectedAudience(AUDIENCE)// 接收者
                    .setVerificationKey(publicKey)// 设置公钥
                    // 设置算法约束
                    .setJwsAlgorithmConstraints(new AlgorithmConstraints(AlgorithmConstraints.ConstraintType.WHITELIST, AlgorithmIdentifiers.RSA_USING_SHA256))
                    .build();

            try {
                // 验证token
                JwtClaims jwtClaims = jwtConsumer.processToClaims(token);
                return jwtClaims.getClaimsMap();
            } catch (Exception e) {
                System.out.println("Token验证失败: " + e.getMessage());
                e.printStackTrace();
                return new HashMap<>();
            }
        } catch (Exception e) {
            System.out.println("Token验证过程发生错误: " + e.getMessage());
            e.printStackTrace();
            return new HashMap<>();
        }
    }

    /**
     * 从token中获取用户ID
     *
     * @param token JWT token
     * @return 用户ID，如果token无效则返回null
     */
    public static Long getUserIdFromToken(String token) {
        Map<String, Object> claims = verify(token);
        return claims.containsKey("userId") ? Long.valueOf(claims.get("userId").toString()) : null;
    }

    /**
     * 从token中获取用户名
     *
     * @param token JWT token
     * @return 用户名，如果token无效则返回null
     */
    public static String getUsernameFromToken(String token) {
        Map<String, Object> claims = verify(token);
        return claims.containsKey("userName") ? claims.get("userName").toString() : null;
    }

    /**
     * 检查token是否过期
     *
     * @param token JWT token
     * @return 如果token有效且未过期返回true，否则返回false
     */
    public static boolean isTokenExpired(String token) {
        Map<String, Object> claims = verify(token);
        if (claims.containsKey("exp")) {
            Date expiration = new Date(Long.parseLong(claims.get("exp").toString()) * 1000);
            return expiration.before(new Date());
        }
        return true;
    }

    /**
     * 生成带有角色的token
     *
     * @param userId   用户ID
     * @param userName 用户名
     * @param role     角色
     * @return JWT token
     */
    @SneakyThrows
    public static String signWithRoles(Long userId, String userName, String role) {
        JwtClaims claims = new JwtClaims();
        // 设置基本声明
        claims.setIssuer(ISSUER);
        claims.setAudience(AUDIENCE);
        claims.setExpirationTimeMinutesInTheFuture(60 * 24);
        claims.setGeneratedJwtId();
        claims.setIssuedAtToNow();
        claims.setNotBeforeMinutesInThePast(2);
        claims.setSubject("eds");

        // 设置用户信息
        claims.setClaim("userId", userId);
        claims.setClaim("userName", userName);
        claims.setClaim("role", "ROLE_" + role.toUpperCase());

        JsonWebSignature jws = new JsonWebSignature();
        jws.setPayload(claims.toJson());

        PrivateKey privateKey = new RsaJsonWebKey(JsonUtil.parseJson(jwtKeyConfig.getPrivateKeyJson())).getPrivateKey();
        jws.setKey(privateKey);
        jws.setKeyIdHeaderValue("keyId");
        jws.setAlgorithmHeaderValue(AlgorithmIdentifiers.RSA_USING_SHA256);

        return jws.getCompactSerialization();
    }

    /**
     * 从token中获取角色列表
     *
     * @param token JWT token
     * @return 角色列表，如果token无效则返回空列表
     */
    @SuppressWarnings("unchecked")
    public static String getRoleFromToken(String token) {
        Map<String, Object> claims = verify(token);
        if (claims.containsKey("role")) {
            Object rolesObj = claims.get("role");
            if (rolesObj instanceof String) {
                return (String) rolesObj;
            }
        }
        return null;
    }

    /**
     * 验证token是否有效
     *
     * @param token JWT token
     * @return 如果token有效返回true，否则返回false
     */
    public static boolean validateToken(String token) {
        try {
            if (token == null || token.isEmpty()) {
                System.out.println("Token为空");
                return false;
            }

            // 如果token不是以Bearer 开头，添加前缀
            if (!token.startsWith("Bearer ")) {
                token = "Bearer " + token;
            }

            // 去掉Bearer 前缀
            String actualToken = token.replace("Bearer ", "");

            Map<String, Object> claims = verify(actualToken);
            if (claims.isEmpty()) {
                System.out.println("Token验证返回空claims");
                return false;
            }

            if (isTokenExpired(actualToken)) {
                System.out.println("Token已过期");
                return false;
            }

            return true;
        } catch (Exception e) {
            System.out.println("Token验证异常: " + e.getMessage());
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 生成带有自定义过期时间的token
     *
     * @param userId            用户ID
     * @param userName          用户名
     * @param expirationMinutes 过期时间（分钟）
     * @return JWT token
     */
    @SneakyThrows
    public static String signWithExpiration(Long userId, String userName, int expirationMinutes) {
        JwtClaims claims = new JwtClaims();
        claims.setIssuer(ISSUER);
        claims.setAudience(AUDIENCE);
        claims.setExpirationTimeMinutesInTheFuture(expirationMinutes);
        claims.setGeneratedJwtId();
        claims.setIssuedAtToNow();
        claims.setNotBeforeMinutesInThePast(2);
        claims.setSubject("eds");
        claims.setClaim("userId", userId);
        claims.setClaim("userName", userName);

        JsonWebSignature jws = new JsonWebSignature();
        jws.setPayload(claims.toJson());

        PrivateKey privateKey = new RsaJsonWebKey(JsonUtil.parseJson(jwtKeyConfig.getPrivateKeyJson())).getPrivateKey();
        jws.setKey(privateKey);
        jws.setKeyIdHeaderValue("keyId");
        jws.setAlgorithmHeaderValue(AlgorithmIdentifiers.RSA_USING_SHA256);

        return jws.getCompactSerialization();
    }

    /**
     * 刷新token（创建新token，保持原有信息）
     *
     * @param token 原token
     * @return 新的token，如果原token无效则返回null
     */
    public static String refreshToken(String token) {
        Long userId = getUserIdFromToken(token);
        String userName = getUsernameFromToken(token);
        String role = getRoleFromToken(token);

        if (userId != null && userName != null) {
            if (!role.isEmpty()) {
                return signWithRoles(userId, userName, role);
            } else {
                return sign(userId, userName);
            }
        }
        return null;
    }

    @Autowired
    public void setJwtKeyConfig(JwtKeyConfig jwtKeyConfig) {
        JwtUtils.jwtKeyConfig = jwtKeyConfig;
    }

}